package com.inspur.edp.bef.core.action.authorityinfo;

import com.inspur.edp.bef.spi.auth.DataPermissionController;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import javax.annotation.Priority;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DataPermissionCtrlProvider {

  private static DataPermissionCtrlProvider instance = new DataPermissionCtrlProvider();
  private Map<String, DataPermissionController> controllers;

  private DataPermissionCtrlProvider() {
  }

  public static DataPermissionCtrlProvider getInstance() {
    return instance;
  }

  private static final String NAME_DEFAULT = "default";

  public DataPermissionController getDefaultController() {
    DataPermissionController rez = getController(NAME_DEFAULT, false);
    return rez == null ? new EmptyDataPermissionController() : rez;
  }

  public DataPermissionController getController(String name, boolean throwe) {
    Objects.requireNonNull(name, "name不允许为空");

    if (controllers == null) {
      buildControllers();
    }
    DataPermissionController rez = controllers.get(name);
    if(rez == null && throwe) {
      throw new RuntimeException("找不到权限控制器:" + name);
    }
    return rez;
  }

  private static final int ORDER_DEFAULT = 0;

  private synchronized void buildControllers() {
    if (controllers != null) {
      return;
    }
    controllers = new HashMap<>();

    ServiceLoader<DataPermissionController> loader = ServiceLoader
        .load(DataPermissionController.class);
    for (DataPermissionController controller : loader) {
      DataPermissionController previous = controllers.putIfAbsent(controller.getName(), controller);
      if (previous != null && compareOrder(previous, controller, ORDER_DEFAULT) > 0) {
        controllers.put(controller.getName(), controller);
      }
    }
  }

  private int compareOrder(Object v1, Object v2, int defaultOder) {
    Priority orderAnno1 = v1.getClass().getAnnotation(Priority.class);
    Priority orderAnno2 = v2.getClass().getAnnotation(Priority.class);
    int order1 = orderAnno1 != null ? orderAnno1.value() : defaultOder;
    int order2 = orderAnno2 != null ? orderAnno2.value() : defaultOder;
    return Integer.compare(order1, order2);
  }
}
